from .abs_quantifier import BaseQuantifier
from ..data_structures.base_structures import DemAttribute, Map, HexCell
from ..config.config import *
from .shp_quantifier_components import *
from .abs_quantifier import BaseQuantifier
import geopandas as gpd
from shapely.geometry import Polygon,MultiPolygon
from tqdm import tqdm
import h3

class ShpQuantifier(BaseQuantifier):

    shp_quantifier_components = [
        # ShpQuantifierComponents.QuantifyBasecellsWithBuilding,
        # ShpQuantifierComponents.QuantifyBasecellsWithSoil,
        # ShpQuantifierComponents.QuantifyBasecellsWithVegetation,
        # ShpQuantifierComponents.QuantifyBasecellsWithWater,
        # ShpQuantifierComponents.QuantifyBasecellsWithRoad,
    ]

    def add_component(component:str):
        ShpQuantifier.shp_quantifier_components.append(component)
    def quantify_hexcells(path:str, map:Map) -> Map:
        """量化shp文件"""
        # 遍历shp文件中的每个几何对象，获取fclass字段和geometry字段
        gdf = gpd.read_file(path)
        for index, row in tqdm(gdf.iterrows(), total=len(gdf), desc="量化"+path):
            fclass = row['fclass']
            geometry = row['geometry']
            # 转为h3.polyfill_geojson所需要的Polygon GeoJSON
            if geometry is None:
                continue
            if isinstance(geometry, MultiPolygon):
                # 遍历 MultiPolygon 中的每个 Polygon
                coordinates = [list(polygon.exterior.coords) for polygon in geometry.geoms]
            elif isinstance(geometry, Polygon):
                # 如果是单个 Polygon，直接获取 exterior
                coordinates = [list(geometry.exterior.coords)]
            else:
                continue
            geojson = {
                "type": "Polygon",
                "coordinates": coordinates
            }
            # 生存每个要素所覆盖的h3单元
            h3indexes = h3.polyfill_geojson(geojson, GlobalConfiguration.h3_resolution)

            # 遍历每个h3单元，从map中找到对应的cell，根据fclass填充attribute数组
            for index in h3indexes:
                if index not in map.cells:
                    continue
                cell:HexCell = map.cells[index]

                # 反射调用方法
                for component in ShpQuantifier.shp_quantifier_components:
                    method_name = component
                    method = getattr(ShpQuantifierComponents, method_name, None)
                    if method is None:
                        raise AttributeError(f"未找到组件方法: {method_name}")
                    try:
                        method(fclass, row, cell)
                    except Exception as e:
                        print(f"调用组件方法 {method_name} 时出错: {e}")

    def quantify_quadcells(path: str, map: Map) -> Map:
        """四角格网量化shp文件"""
        gdf = gpd.read_file(path)

        for index, row in tqdm(gdf.iterrows(), total=len(gdf), desc="量化"+path):
            fclass = row['fclass']
            geometry = row['geometry']
            if geometry is None:
                continue
            if isinstance(geometry, MultiPolygon):
                # 遍历 MultiPolygon 中的每个 Polygon
                coordinates = [list(polygon.exterior.coords) for polygon in geometry.geoms]
            elif isinstance(geometry, Polygon):
                # 如果是单个 Polygon，直接获取 exterior
                coordinates = [list(geometry.exterior.coords)]
            geojson = {
                "type": "Polygon",
                "coordinates": coordinates
            }

            geohash_codes = BaseQuantifier.geohash_polyfill_geojson(geojson, GlobalConfiguration.geohash_resolution)
            for index in geohash_codes:
                if index not in map.cells:
                    continue
                cell:QuadCell = map.cells[index]
                # 反射调用方法
                for component in ShpQuantifier.shp_quantifier_components:
                    method_name = component
                    method = getattr(ShpQuantifierComponents, method_name, None)
                    if method is None:
                        raise AttributeError(f"未找到组件方法: {method_name}")
                    try:
                        method(fclass, row, cell)
                    except Exception as e:
                        print(f"调用组件方法 {method_name} 时出错: {e}")
